LS.scoreboard = {
    getRowHTML: function(rank, username, point,penalty) {
        return "<span class='scoreboard_rank'>"+rank+"</span><span class='scoreboard_user'>"+$('<div/>').text(username).html()+"</span><span class='scoreboard_point'>"+point+"</span><span class='scoreboard_penalty'>"+Math.round(penalty*100)/100+"</span>";
    },
    init: function(workspace) {
        this.spacing = 25;
        this.workspace = $(workspace);
        this.tmpdom = null;
        this.alertbox = new LS.notifier('#scoreboard_error');
        
        this.userScoreboard = [];
    },
    onLogout: function() {
        this.alertbox.destroy();
        this.workspace.children("div.scoreboard_ranklist").remove().each(function(){delete this;});
    },
    newRow: function(uid, html) {
        if(!this.tmpdom) this.tmpdom = document.createDocumentFragment();
        
        var elem = document.createElement("div");
        $(elem).attr('id', 'rl'+uid)
               .attr('user_id', uid)
               .addClass('scoreboard_ranklist')
               .html(html);
        
        this.tmpdom.appendChild(elem);
        
        return $(elem);
    },
    update: function(list, animate) {
        // stop animating
        $('div.scoreboard_ranklist').stop();
        this.workspace.stop();
        
        // hide rows which are being disappeared.
        $('div.scoreboard_ranklist').each(function(){
            for(var i in list) {
                if($(this).attr('user_id') == list[i].User.id) return;
            }
            $(this).fadeOut(300);
        });
        
        // update the rank of every user
        var i, last = null, last_panelty = 0, rank = 0, last_rank = 0;
        for(i in list) {
            var u = list[i];
            
            // detect same rank
            rank++;
            if(last == null || u[0].point != last) {
                last = u[0].point;
                last_penalty = u[0].penalty;
                last_rank = rank;
            } else if(u[0].penalty == 0 || u[0].penalty != last_penalty) {
                last_penalty = u[0].penalty;
                last_rank = rank;
            }
            
            // prepare HTML
            var html = this.getRowHTML(last_rank, u.User.username, u[0].point,u[0].penalty);
            
            // find that element
            // create a new row if not exists.
            var elem = $('#rl'+u.User.id);
            
            if(!elem.length) {
                elem = this.newRow(u.User.id, html);
            } else {
                elem.html(html);
            }
            
            // prepare css (eg. position)
            var targetcss = {top: i*this.spacing+'px'};
            // only show when hidden or not animating
            if(elem.is(':hidden') || !animate) {
                elem.css(targetcss).fadeIn(300);
            } else {
                elem.animate(targetcss).show();
            }
        }
        
        // append new row onto the scoreboard
        if(this.tmpdom) {
            this.workspace.append(this.tmpdom);
            this.tmpdom = null;
        }
        
        // resize the scoreboard
        var sb_h = (Math.floor(i)+2)*this.spacing;
        var sb_css = {height: sb_h+'px'};
        if(animate) {
            this.workspace.animate(sb_css);
        } else {
            this.workspace.css(sb_css);
        }
    },
    updateUserScoreboard: function(json_sb) {
        var changed = 0;
        for(var i in json_sb) {
            if(this.userScoreboard[json_sb[i].Scoreboard.problem_id]) {
                if(this.userScoreboard[json_sb[i].Scoreboard.problem_id].open != 2 && json_sb[i].Problem.open == 2)
                changed = 1;
            }
            this.userScoreboard[json_sb[i].Scoreboard.problem_id] = {
                answer: json_sb[i].Scoreboard.answer,
                point: json_sb[i].Scoreboard.point,
                penalty: json_sb[i].Scoreboard.penalty,
                open: json_sb[i].Problem.open,
                real_answer: ((json_sb[i].Problem.open == 2)?(json_sb[i].Problem.ans):null)
            };
        }
        if(changed == 1) {
            LS.problem.updateUserAnswerStatus();
        }
    },
    /* Access user scoreboard */
    getUserAnswer: function(problem_id) {
        if(this.userScoreboard[problem_id]) {
            return this.userScoreboard[problem_id].answer;
        } else {
            return null;
        }
    },
    getUserScoreboardRealAnswer: function(problem_id) {
        if(this.userScoreboard[problem_id]) {
            return this.userScoreboard[problem_id].real_answer;
        } else {
            return null;
        }
    },
    /* Reload */
    reload: function() {
        this.reloadScoreboard();
        this.reloadUserScoreboard();
    },
    reloadScoreboard: function() {
        $.ajax({
            url: LS.getURL("scoreboards"),
            type: "GET",
            dataType: "json",
            error: function(xhr) {
                LS.scoreboard.alertbox.showError(LS.localized.scoreboardErrorConnection);
            },
            success: function(response) {
                LS.ajaxReturnedTimestamp(response);
                LS.scoreboard.alertbox.showError(null);
                
                if(response.scoreboard.success) {
                    LS.scoreboard.update(response.scoreboard.scoreboard, true);
                } else {
                    LS.scoreboard.alertbox.showError((response.scoreboard.errmsg) ? response.scoreboard.errmsg : LS.localized.temporaryError);
                }
            }
        });
    },
    reloadUserScoreboard: function() {
        $.ajax({
            url: LS.getURL("scoreboards/user_scoreboard"),
            type: "GET",
            dataType: "json",
            error: function(xhr) {
                LS.scoreboard.alertbox.showError(LS.localized.scoreboardErrorConnection);
            },
            success: function(response) {
                LS.ajaxReturnedTimestamp(response);
                LS.scoreboard.alertbox.showError(null);
                
                if(response.scoreboard) {
                    LS.scoreboard.updateUserScoreboard(response.scoreboard);
                } else {
                    LS.scoreboard.alertbox.showError((response.scoreboard.errmsg) ? response.scoreboard.errmsg : LS.localized.temporaryError);
                }
            }
        });
    }
};
